package leetcode;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import sun.misc.Signal;
import sun.misc.SignalHandler;

public class JavaStopGraceFully {

	public static int len = 5;

	static ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(1000);

	static ExecutorService executorService = Executors.newFixedThreadPool(3);

	static volatile AtomicBoolean stopPut = new AtomicBoolean(false);
	static volatile AtomicBoolean stopPoll = new AtomicBoolean(false);
	static volatile AtomicBoolean readyExitFlag = new AtomicBoolean(false);

	public static void main(String[] args) throws InterruptedException {

		executorService.submit(new Runnable() {
			@Override
			public void run() {

				while (true) {
					for (int i = 0; i < len + 1; i++) {
						try {
							queue.put(i);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					try {
						TimeUnit.SECONDS.sleep(len);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					if (stopPut.get()) {
						break;
					}
				}
				System.out.println("exit put thread.");
			}
		});

		executorService.submit(new Runnable() {
			@Override
			public void run() {
				while (true) {
					Integer ele = queue.poll();
					System.out.println(ele);
					try {
						TimeUnit.SECONDS.sleep(1L);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					if (stopPoll.get()) {
						break;
					}
				}
				System.out.println("exit poll thread.");
			}
		});

		executorService.submit(new Runnable() {
			@Override
			public void run() {

				while (true) {
					if (!stopPut.get()) {
						continue;
					}
					if (stopPut.get()) {
						if (0 == queue.size()) {
							stopPoll.set(true);
							readyExitFlag.set(true);
						}
					}
					if (readyExitFlag.get()) {
						break;
					}
					try {
						TimeUnit.SECONDS.sleep(1L);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println("exit loop thread.");
				if (readyExitFlag.get()) {
					System.out.println("exit gracefully.");
					System.exit(0);
				}
			}
		});

		SignalHandler sh = new SignalHandler() {
			@Override
			public void handle(Signal signal) {

				System.out
						.println(signal.getName() + ".." + signal.getNumber());

				if (signal.getName().equals("INT")
						|| signal.getName().equals("TERM")) {

					if (readyExitFlag.get()) {
						System.out.println("exit gracefully.");
						System.exit(0);
					} else {
						if (stopPut.get()) {
							System.out.println("wait for pop done.");
						} else {
							stopPut.set(true);
						}
					}
				}
			}
		};

		Signal.handle(new Signal(System.getProperties().getProperty("os.name")
				.toLowerCase().startsWith("win") ? "INT" : "TERM"), sh);

	}
}
